﻿using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.Threading;
using System.Collections;
using Pixysoft.Collections;

namespace Pixysoft.Cache
{
    /// <summary>
    /// ObjectCache 的摘要说明
    /// </summary>
    [Serializable]
    public class ObjectCache<T> : IEnumerable<T>, IEnumerator<T>
    {
        int index = -1;

        public delegate void CacheExpired(T obj);

        public CacheExpired OnCacheExpired;

        protected ArrayList list = new ArrayList();

        private static object syncRoot = new Object();


        public T Remove(string token)
        {
            ObjectTokenPair<T> value = _Get(token);

            lock (list.SyncRoot)
            {
                list.Remove(value);
            }

            if (value == null)
                return default(T);
            else
                return value.Obj;
        }

        public void RemoveByValue(T value)
        {
            if (value == null)
                return;

            ObjectTokenPair<T> pair = _GetByValue(value);

            if (pair == null)
                return;

            list.Remove(pair);
        }

        public void Add(string token, T obj)
        {
            if (obj == null)
                return;

            Remove(token);

            lock (list.SyncRoot)
            {
                list.Add(new ObjectTokenPair<T>(token, obj));
            }
        }

        public void Add(string token, T obj, DateTime endTime)
        {
            if (obj == null)
                return;

            Remove(token);

            lock (list.SyncRoot)
            {
                list.Add(new ObjectTokenPair<T>(token, obj, endTime));
            }
        }

        public void Add(string token, T obj, int secondspans)
        {
            if (obj == null)
                return;

            if (secondspans <= 0)
                return;

            DateTime endTime = Pixysoft.Tools.GlobalTimer.Instance.GetGlobalTime().AddSeconds(secondspans);

            this.Add(token, obj, endTime);
        }


        public bool Extend(string token, DateTime endTime)
        {
            T obj = Get(token);

            if (obj == null)
                return false;

            Add(token, obj, endTime);

            return true;
        }

        public bool Extend(string token, int secondspans)
        {
            if (secondspans <= 0)
                return false;

            DateTime endTime = Pixysoft.Tools.GlobalTimer.Instance.GetGlobalTime().AddSeconds(secondspans);

            return Extend(token, endTime);
        }

        public bool Contains(string token)
        {
            return Get(token) != null;
        }

        public bool ContainsValue(T value)
        {
            lock (list.SyncRoot)
            {
                foreach (ObjectTokenPair<T> pair in list)
                {
                    if (pair.Obj.Equals(value))
                        return true;
                }
            }

            return false;
        }

        public void Clear()
        {
            list.Clear();
        }

        public T Get(string token)
        {
            RemoveExpiredPair();

            lock (list.SyncRoot)
            {
                foreach (ObjectTokenPair<T> pair in list)
                {
                    if (pair.Token == token)
                        return pair.Obj;
                }
            }

            return default(T);
        }

        private ObjectTokenPair<T> _Get(string token)
        {
            RemoveExpiredPair();

            lock (list.SyncRoot)
            {
                foreach (ObjectTokenPair<T> pair in list)
                {
                    if (pair.Token == token)
                        return pair;
                }
            }

            return null;
        }

        private ObjectTokenPair<T> _GetByValue(T value)
        {
            lock (list.SyncRoot)
            {
                foreach (ObjectTokenPair<T> pair in list)
                {
                    if (pair.Obj.Equals(value))
                        return pair;
                }
            }

            return null;
        }

        public void RemoveExpiredPair()
        {
            List<ObjectTokenPair<T>> removelist = new List<ObjectTokenPair<T>>();

            lock (list.SyncRoot)
            {
                foreach (ObjectTokenPair<T> pair in list)
                {
                    if (pair.IsExpired)
                        removelist.Add(pair);
                }
            }

            foreach (ObjectTokenPair<T> pair in removelist)
            {
                if (OnCacheExpired != null)
                    OnCacheExpired(pair.Obj);

                lock (list.SyncRoot)
                {
                    list.Remove(pair);
                }
            }
        }

        public bool IsEmpty
        {
            get { return list.Count == 0; }
        }

        #region IEnumerator<T> 成员

        public T Current
        {
            get { return (list[index] as ObjectTokenPair<T>).Obj; }
        }

        public void Dispose()
        {
            Reset();
        }

        object IEnumerator.Current
        {
            get { return list[index]; }
        }

        public bool MoveNext()
        {
            if (index >= list.Count - 1)
                return false;

            index++;

            return true;
        }

        public void Reset()
        {
            index = -1;
        }

        public IEnumerator<T> GetEnumerator()
        {
            return this;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this;
        }

        #endregion
    }
}

[Serializable]
public class ObjectTokenPair<T>
{
    T obj;
    string token;
    DateTime endTime = DateTime.MinValue;

    public ObjectTokenPair() { }
    public ObjectTokenPair(string token, T obj)
    {
        this.obj = obj;

        this.token = token;
    }
    public ObjectTokenPair(string token, T obj, DateTime endTime)
    {
        this.obj = obj;

        this.token = token;

        this.endTime = endTime;
    }


    public T Obj
    {
        get { return obj; }
        set { obj = value; }
    }
    public string Token
    {
        get { return token; }
        set { token = value; }
    }
    public DateTime EndTime
    {
        get { return endTime; }
        set { endTime = value; }
    }
    public bool IsExpired
    {
        get
        {
            if (endTime == DateTime.MinValue)
                return false;

            //bug!! 不能使用DateTime.Now 判断

            if (Pixysoft.Tools.GlobalTimer.Instance.GetGlobalTime() > endTime)
                return true;

            return false;
        }
    }

}